﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WorkflowCore.Interface;
using WorkflowCore.Models;
using WorkflowCore.Models.DefinitionStorage.v1;
using WorkflowCore.Services.DefinitionStorage;
using WorkflowCore2210A.Application.Dto;
using WorkflowCore2210A.Application.Dto.Input;
using WorkflowCore2210A.Application.Dto.Output;
using WorkflowCore2210A.Application.Steps;
using WorkflowCore2210A.Domain;
using WorkflowCore2210A.Domain.Model;
using Yitter.IdGenerator;

namespace WorkflowCore2210A.Application
{
    public class WorkflowService : IWorkflowService
    {
        private readonly IBaseRepository<WorkflowDefinitionModel> _repository;
        private readonly IBaseRepository<AuditModel> _auditRepository;
        private readonly IBaseRepository<WorkflowInstanceModel> _workflowInstanceRepository;
        private readonly IMapper _mapper;
        /// <summary>
        /// 流程注册接口
        /// </summary>
        private readonly IWorkflowRegistry _workflowRegistry;
        /// <summary>
        /// 流程加载接口（用来将数据库的流程定义数据加载到引擎中）
        /// </summary>
        private readonly IDefinitionLoader _definitionLoader;

       // private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IBaseRepository<FormTemplateModel> _formTemplateRepository;


        public WorkflowService(IBaseRepository<WorkflowDefinitionModel> repository,
             IMapper mapper,
             IWorkflowRegistry workflowRegistry,
             IDefinitionLoader definitionLoader,
             IBaseRepository<AuditModel> auditRepository,
             IBaseRepository<WorkflowInstanceModel> workflowInstanceRepository,
             //IHttpContextAccessor httpContextAccessor,
             IBaseRepository<FormTemplateModel> formTemplateRepository)
        {
            _repository = repository;
            _mapper = mapper;
            _workflowRegistry = workflowRegistry;
            _definitionLoader = definitionLoader;
            _auditRepository = auditRepository;
            _workflowInstanceRepository = workflowInstanceRepository;
            //_httpContextAccessor = httpContextAccessor;
            _formTemplateRepository = formTemplateRepository;
        }
        
        /// <summary>
        ///  添加流程定义（添加到数据库）
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiResult<int> AddWorkflowDefinition(WorkflowDefinitionInput input)
        {
            var entity = _mapper.Map<WorkflowDefinitionModel>(input);
            entity.ID = YitIdHelper.NextId().ToString();
            entity.Steps = JsonConvert.SerializeObject(input.Steps);
            _repository.Add(entity);

            // 加载流程设计到引擎中
            LoadDefinition(entity);

            return new ApiResult<int>()
            {
                Code = Enums.StatueCode.Ok,
                Data = 1,
                Message = "流程添加成功"
            };
        }

        public void LoadDefinition(WorkflowDefinitionModel model)
        {
            // 判断是否注册了
            if (_workflowRegistry.IsRegistered(model.DefinitionId, model.Version))
            {
                return;
            }

            var steps = JsonConvert.DeserializeObject<List<StepNode>>(model.Steps);
            if (steps!=null && steps.Any())
            {
                // 创建引擎能够识别流程设计对象
                DefinitionSourceV1 source = new()
                {
                    Id = model.DefinitionId,
                    DataType = $"{typeof(Dictionary<string, object>).FullName},{typeof(Dictionary<string, object>).Assembly.FullName}",
                    Version = model.Version,
                    Description = model.Title
                };

                // 创建步骤
                StepSourceV1 start = new()
                {
                    Id = nameof(StartStep),
                    Name = "发起",
                    NextStepId = steps.First().StepId,
                    StepType = $"{typeof(StartStep).FullName},{typeof(StartStep).Assembly.FullName}",
                };
                source.Steps.Add(start);

                foreach (var s in steps)
                {
                    StepSourceV1 audit = new()
                    {
                        Id = s.StepId,
                        Name =s.StepName,
                        NextStepId = s.NextStepId,
                        StepType = $"{typeof(AuditStep).FullName},{typeof(AuditStep).Assembly.FullName}",
                    };
                    audit.Inputs.TryAdd(nameof(s.AuditUserId),$"\"{s.AuditUserId}\"");
                    audit.Inputs.TryAdd(nameof(s.AuditUserName), $"\"{s.AuditUserName}\"");

                    source.Steps.Add(audit);
                }

                StepSourceV1 end = new()
                {
                    Id = nameof(EndStep),
                    Name = "结束",
                    StepType = $"{typeof(EndStep).FullName},{typeof(EndStep).Assembly.FullName}",
                };
                source.Steps.Add(end);

                var json = JsonConvert.SerializeObject(source);
                _definitionLoader.LoadDefinition(json, Deserializers.Json);
            }
        }


        /// <summary>
        /// 添加审批记录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public int AddAudit(AddAuditInput input)
        {
            var entity = _mapper.Map<AuditModel>(input);
            entity.ID = YitIdHelper.NextId().ToString();
            entity.Status = input.Status;
            entity.AuditOperation = "";
            entity.Remark = string.Empty;
            return _auditRepository.Add(entity);
        }

        /// <summary>
        /// 更新审批记录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public int UpdateAudit(UpdateAuditInput input)
        {
            // AsTracking: 跟踪
            //  查询当前正在审批的记录
            var entity = _auditRepository.GetAll().AsTracking()
                .FirstOrDefault(p => p.WorkflowId == input.WorkflowId 
                                && p.AuditUserId == input.AuditUserId);
            entity.Status = true;
            entity.AuditOperation = input.AuditOperation;
            entity.Remark = input.Remark;
            entity.UpdateTime = DateTime.Now;
            //entity.UpdatedUserId = 0;

            return _auditRepository.Update(entity);
        }

        /// <summary>
        /// 判断是否有权限审批
        /// </summary>
        /// <param name="workflowId">流程实例ID</param>
        /// <param name="userId">待审批用户</param>
        /// <param name="stepId">当前审批步骤</param>
        /// <returns></returns>
        public bool HasAudit(string workflowId, long userId)
        {
            return _auditRepository.GetAll().Any(p => 
                                                    p.WorkflowId == workflowId
                                                    && !p.Status 
                                                    && p.AuditUserId == userId);
        }


        /// <summary>
        /// 添加流程业务实例
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public int AddWorkflowInstance(AddWorkflowInstanceInput input)
        {
            var entity = _mapper.Map<WorkflowInstanceModel>(input);
            entity.ID = YitIdHelper.NextId().ToString() ;
            entity.Status = "处理中";
            return _workflowInstanceRepository.Add(entity);
        }

        /// <summary>
        /// 流程定义分页查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiPaging<WorkflowDefinitionOutput> GetWorkflowDefinitionList(PageInput input)
        {
            // AutoMapper: 作用是避免属性手动赋值
            // ToList,Count,FirstOrDefault,First,Single 等等方法会立即执行数据库。
            var query = _repository.GetAll().AsNoTracking();

            var list = query.Skip((input.PageIndex-1)*input.PageSize).Take(input.PageSize).ToList();
            var data = _mapper.Map<List<WorkflowDefinitionOutput>>(list);

            return new ApiPaging<WorkflowDefinitionOutput>()
            {
                Code = Enums.StatueCode.Ok,
                PageList = data,
                Message = "查询完毕",
                TotalCount = query.Count()
            };
        }


        /// <summary>
        /// 流程实例查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiPaging<WorkflowInstanceOutput> GetWorkflowInstanceList(QueryWorkflowInstalceInput input)
        {
            var query = _workflowInstanceRepository.GetAll().AsNoTracking();
            if (!string.IsNullOrWhiteSpace(input.Title))
            {
                query = query.Where(p => p.Title.Contains(input.Title));
            }
            if(input.BeginTime!=null )
            {
                query = query.Where(p => p.CreatedTime >= input.BeginTime );
            }
            if (input.EndTime != null) 
            {
                query=query.Where(p => p.CreatedTime <= input.EndTime);
            }
            // 分页查询
            var list = query.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToList();
            var count = query.Count();
            var data = _mapper.Map<List<WorkflowInstanceOutput>>(list);

            return new ApiPaging<WorkflowInstanceOutput>()
            {
                Code = Enums.StatueCode.Ok,
                PageList = data,
                Message = "查询完毕",
                TotalCount = query.Count()
            };
        }

        /// <summary>
        /// 获取我的待办
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiPaging<AuditOutput> GetAuditList(PageInput input,long userId)
        {
            // 获取当前登录人ID（从Playload中获取）
           /* var currentUserId = Convert.ToInt64(_httpContextAccessor.HttpContext!.User
                .FindFirst(JwtRegisteredClaimNames.Sub)!.Value);*/

            var query = _auditRepository.GetAll().Where(p=>p.AuditUserId==userId
                                                            && !p.Status);
            // 分页查询
            var list = query.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToList();
            var count = query.Count();
            var data = _mapper.Map<List<AuditOutput>>(list);
            return new ApiPaging<AuditOutput>()
            {
                Code = Enums.StatueCode.Ok,
                PageList = data,
                Message = "查询完毕",
                TotalCount = count
            };
        }

        /// <summary>
        /// 保存表单模版
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiResult<int> SaveFormTemplate(SaveFormTemplateInput input)
        {
            // 判断流程模板下，表单是否存在，如果不存在，则做添加，否则做更新
            var entity = _formTemplateRepository.GetAll().AsTracking()
                .FirstOrDefault(p => p.DefinitionModelId == input.DefinitionModelId);
            if (entity == null)
            {

                var model = new FormTemplateModel()
                {
                    DefinitionModelId = input.DefinitionModelId,
                };
                model.ID = YitIdHelper.NextId().ToString();
                model.FormBodyJson = JsonConvert.SerializeObject(input.FormFields);
                _formTemplateRepository.Add(model);
            }
            else
            {
                entity.FormBodyJson = JsonConvert.SerializeObject(input.FormFields);
                entity.UpdateTime = DateTime.Now;
                _formTemplateRepository.Update(entity);
            }

            return new ApiResult<int>()
            {
                Code = Enums.StatueCode.Ok,
                Message = "保存成功",
                Data = 1
            };
        }

        /// <summary>
        /// 获取表单模版
        /// </summary>
        /// <param name="definitionModelId"></param>
        /// <returns></returns>
        public ApiResult<FormTemplateOutput> GetFormTemplate(long definitionModelId)
        {
            var entity = _formTemplateRepository.GetAll()
                .FirstOrDefault(p => p.DefinitionModelId == definitionModelId);

            if (entity == null)
            {
                return new ApiResult<FormTemplateOutput>()
                {
                    Code = Enums.StatueCode.Ok,
                    Message = "暂无数据",
                    Data = new FormTemplateOutput()
                    {
                        DefinitionModelId = definitionModelId,
                        FormFields = new List<FormField>()
                    }
                };
            }
            var definitionModel = _repository.GetAll().FirstOrDefault(p=>p.ID ==definitionModelId.ToString());
            FormTemplateOutput result = new()
            {
                DefinitionModelId = entity.DefinitionModelId,
                DefinitionTitle = definitionModel.Title,
                FormFields = JsonConvert.DeserializeObject<List<FormField>>(entity.FormBodyJson)
            };

            return new ApiResult<FormTemplateOutput>()
            {
                Code = Enums.StatueCode.Ok,
                Message = "查询成功",
                Data = result
            };
        }


        /// <summary>
        /// 获取流程实例详情
        /// </summary>
        /// <param name="workflowId"></param>
        /// <returns></returns>
        public ApiResult<WorkflowInstalceDetailOutput> GetWorkflowDetail(string workflowId)
        {
            WorkflowInstalceDetailOutput result = new();
            var workflowInstance = _workflowInstanceRepository.GetAll()
                .FirstOrDefault(p => p.WorkflowId == workflowId);

            // 获取流程实例
            result.WorkflowInstance = _mapper.Map<WorkflowInstanceOutput>(workflowInstance);

            // 获取审核记录
            var audit = _auditRepository.GetAll()
                .Where(p => p.WorkflowId == workflowId)
                .OrderByDescending(p => p.UpdateTime)
                .ToList();
            result.AuditList = _mapper.Map<List<AuditOutput>>(audit);

            // 获取表单数据
            result.FormData = workflowInstance.FormData;

            return new ApiResult<WorkflowInstalceDetailOutput>()
            {
                Code = Enums.StatueCode.Ok,
                Message = "查询成功",
                Data = result
            };
        }
    }
}
